package org.ian.client;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.annotation.SessionScope;

import java.util.Map;


@Component
@SessionScope
public class TokenTask {
    @Autowired
    RestTemplate restTemplate;
    public String access_token = "";
    public String refresh_token = "";

    public String getData(String code) {
        if ("".equals(access_token) && code != null) {
            MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
            map.add("code", code);
            map.add("client_id", "javaboy");
            map.add("client_secret", "123");
            map.add("redirect_uri", "http://localhost:8082/index.html");
            map.add("grant_type", "authorization_code");
            /*
            远程调用http://localhost:8127/oauth/token 后，相应的token会存入redis
            如果内存或数据库中的客户端信息中，authorized_grant_types字段的值包含 authorization_code，那么会将access_token保存到redis，
            存入redis的记录有4条，分别是：uname_to_access:javaboy:javaboy，auth_to_access:e099d10c8756c98b83381179a6ff039b，
                                     auth:ffe63f30-322d-4ff7-9db6-3b1c20e13d92，access:ffe63f30-322d-4ff7-9db6-3b1c20e13d92

            如果内存或数据库中的客户端信息中，authorized_grant_types字段的值包含refresh_token，那么这里还会将refresh_token保存到redis，
            总共会保存如下9条记录：
            access_to_refresh:7a7af29f-bdaf-4885-b2f6-de53e3678b6f
            uname_to_access:javaboy:javaboy
            auth_to_access:e099d10c8756c98b83381179a6ff039b
            client_id_to_access:javaboy
            refresh_auth:9a31b230-f336-47d7-b421-cd9ce59905c9
            auth:7a7af29f-bdaf-4885-b2f6-de53e3678b6f
            refresh_to_access:9a31b230-f336-47d7-b421-cd9ce59905c9
            access:7a7af29f-bdaf-4885-b2f6-de53e3678b6f
            refresh:9a31b230-f336-47d7-b421-cd9ce59905c9
             */
            Map<String, String> resp = restTemplate.postForObject("http://localhost:8127/oauth/token", map, Map.class);
            access_token = resp.get("access_token");
            refresh_token = resp.get("refresh_token");
            return loadDataFromResServer();
        } else {
            return loadDataFromResServer();
        }
    }

    private String loadDataFromResServer() {
        try {
            HttpHeaders headers = new HttpHeaders();
            headers.add("Authorization", "Bearer " + access_token);
            HttpEntity<Object> httpEntity = new HttpEntity<>(headers);
            ResponseEntity<String> entity = restTemplate.exchange("http://localhost:8081/common/hello", HttpMethod.GET, httpEntity, String.class);
            return entity.getBody();
        } catch (RestClientException e) {
            e.printStackTrace();
            return "未加载";
        }
    }

    /**
     * 定时刷新token，获取新的access_token和refresh_token
     * 定时任务含义：0点55分执行1次，然后每隔1小时执行一次
     *
     * 序号	说明	必填	允许填写的值	允许的通配符
     * 1	秒	是	0-59	, - * /
     * 2	分	是	0-59	, - * /
     * 3	时	是	0-23	, - * /
     * 4	日	是	1-31	, - * ? / L W
     * 5	月	是	1-12 / JAN-DEC	, - * /
     * 6	周	是	1-7 or SUN-SAT	, - * ? / L #
     * 7	年	否	1970-2099	, - * /
     *
     * 通配符说明:
     * * 表示所有值。 例如:在分的字段上设置 *,表示每一分钟都会触发。
     * ? 表示不指定值。使用的场景为不需要关心当前设置这个字段的值。例如:要在每月的10号触发一个操作，但不关心是周几，所以需要周位置的那个字段设置为”?” 具体设置为 0 0 0 10 * ?
     * - 表示区间。例如 在小时上设置 “10-12”,表示 10,11,12点都会触发。
     * , 表示指定多个值，例如在周字段上设置 “MON,WED,FRI” 表示周一，周三和周五触发
     * / 用于递增触发。如在秒上面设置”5/15” 表示从5秒开始，每增15秒触发(5,20,35,50)。 在日字段上设置’1/3’所示每月1号开始，每隔三天触发一次。
     * L 表示最后的意思。在日字段设置上，表示当月的最后一天(依据当前月份，如果是二月还会依据是否是润年[leap]), 在周字段上表示星期六，相当于”7”或”SAT”。如果在”L”前加上数字，则表示该数据的最后一个。例如在周字段上设置”6L”这样的格式,则表示“本月最后一个星期五”
     * W 表示离指定日期的最近那个工作日(周一至周五). 例如在日字段上置”15W”，表示离每月15号最近的那个工作日触发。如果15号正好是周六，则找最近的周五(14号)触发, 如果15号是周未，则找最近的下周一(16号)触发.如果15号正好在工作日(周一至周五)，则就在该天触发。如果指定格式为 “1W”,它则表示每月1号往后最近的工作日触发。如果1号正是周六，则将在3号下周一触发。(注，”W”前只能设置具体的数字,不允许区间”-“)。
     * # 序号(表示每月的第几个周几)，例如在周字段上设置”6#3”表示在每月的第三个周六.注意如果指定”#5”,正好第五周没有周六，则不会触发该配置(用在母亲节和父亲节再合适不过了) ；小提示：’L’和 ‘W’可以一组合使用。如果在日字段上设置”LW”,则表示在本月的最后一个工作日触发；周字段的设置，若使用英文字母是不区分大小写的，即MON与mon相同
     */
    @Scheduled(cron = "0 55 0/1 * * ?")
    public void tokenTask() {
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("client_id", "javaboy");
        map.add("client_secret", "123");
        map.add("refresh_token", refresh_token);
        map.add("grant_type", "refresh_token");
        Map<String, String> resp = restTemplate.postForObject("http://localhost:8127/oauth/token", map, Map.class);
        access_token = resp.get("access_token");
        refresh_token = resp.get("refresh_token");
    }
}
